﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace vJine.Lua.GUI.UI {
    /// <summary>
    /// NodeStatus.xaml 的交互逻辑
    /// </summary>
    public partial class NodeStatus : UserControl {
        public NodeStatus() {
            InitializeComponent();
        }

        private void btnRun_Click(object sender, RoutedEventArgs e) {
            lock (this) {
                switch (this.currentStatus) {
                    case xStatus.Idle:
                        this.switch_status(xStatus.Run);
                        break;
                    case xStatus.Run:
                        this.switch_status(xStatus.Pause);
                        break;
                    case xStatus.Pause:
                        this.switch_status(xStatus.Continue);
                        break;
                    case xStatus.Error:
                        this.switch_status(xStatus.Retry);
                        break;
                    default:
                        break;
                };
            }
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e) {
            lock (this) {
                this.switch_status(xStatus.Cancel);
            }
        }

        private void btnIgnore_Click(object sender, RoutedEventArgs e) {
            lock (this) {
                this.switch_status(xStatus.Ignore);
            }
        }

        #region

        NodeConfig luaConfig { get; set; }
        LuaContext luaContext { get; set; }
        Action<string> on_log = null;
        Action<string> on_warn = null;

        vJine.Core.Call<bool?, string> on_error = null;
        AutoResetEvent execAsyncSignal = new AutoResetEvent(false);
        public void set_bound(LuaContext luaContext, NodeConfig luaConfig) {
            this.DataContext = luaConfig;

            this.luaContext = luaContext;
            this.luaConfig = luaConfig;

            this.luaParams.IsResult = false;
            this.luaParams.luaContext = luaContext;
            this.luaResults.IsResult = true;
            this.luaResults.luaContext = luaContext;

            if (luaConfig.configs == null || luaConfig.configs.Count == 0) {
                this.luaParams.set_bound(null);
                this.luaResults.set_bound(null);
            } else {
                this.luaParams.set_bound(luaConfig.configs);
                this.luaResults.set_bound(luaConfig.configs);
            }

            int tab_index = this.luaConfig.tab;
            if (tab_index < 0 || tab_index > 2) {
                tab_index = 0;
            }
            this.tcMain.SelectedIndex = tab_index;

            Action check_pause = () => {
                lock (this) {
                    if (this.currentStatus != xStatus.Pause) {
                        return;
                    }

                    this.message_new("[日志] 程序暂停", 
                        new SolidColorBrush(Colors.YellowGreen));
                }

                this.execAsyncSignal.WaitOne();
                switch (this.currentStatus) {
                    case xStatus.Continue:
                        break;
                    default:
                        throw vJine.Core.CoreException.Cancel;
                }
            };

            Brush logBrush = new SolidColorBrush(Colors.DarkBlue);
            this.on_log = (string log_msg) => {
                this.message_new("[日志] " +  log_msg, logBrush);

                check_pause();
            };
            this.luaContext.reg("on_log", on_log);

            Brush warnBrush = new SolidColorBrush(Colors.DarkCyan);
            
            this.on_warn =  (string warn_msg) => {
                this.message_new("[警告] " + warn_msg, warnBrush);

                check_pause();
            };
            this.luaContext.reg("on_warn", on_warn);

            Brush errorBrush = new SolidColorBrush(Colors.OrangeRed);
            
            this.on_error = (string err_msg) => {
                this.message_new("[错误] " + err_msg, errorBrush);

                if (this.currentStatus == xStatus.Idle) {
                    return null;
                }

                this.switch_status(xStatus.Error);
                this.execAsyncSignal.WaitOne();

                lock (this) {
                    switch (this.currentStatus) {
                        case xStatus.Retry:
                            return true;
                        case xStatus.Ignore:
                            return false;
                        case xStatus.Cancel:
                            return null;
                    }
                    return null;
                }
            };
            this.luaContext.reg("on_error", on_error);

            this.runContext = () => {
                this.message_clear();
                try {
                    this.on_log("[运行开始]");
                    this.luaConfig.run(this.luaContext);
                    this.on_log("[运行结束]");
                } catch (Exception ex) {
                    if (ex.InnerException != null) {
                        ex = ex.InnerException;
                    }

                    if (ex == vJine.Core.CoreException.Cancel) {
                        this.on_warn("[运行取消]");
                    }
                } finally {
                    try {
                        this.luaContext.gc();
                    } catch (Exception ex) {
                        if (ex.InnerException != null) {
                            ex = ex.InnerException;
                        }

                        this.execAsyncSignal.Set();
                        this.on_error("回收资源错误, " + ex.Message);
                    }
                }
            };
        }

        enum xStatus {
            Idle,
            Run,

            Pause,
            Continue,

            Error,
            Retry,

            Ignore,
            Cancel            
        }

        xStatus currentStatus = xStatus.Idle;
        void switch_status(xStatus status) {
            this.Dispatcher.Invoke((Action)delegate() {
                switch (status) {
                    case xStatus.Idle:
                        this.btnRun.IsEnabled = true;
                        this.btnRun.Content = "运行";

                        this.btnCancel.IsEnabled = false;
                        this.btnIgnore.IsEnabled = false;
                        break;
                    case xStatus.Run:
                        this.btnRun.IsEnabled = true;
                        this.btnRun.Content = "暂停";
                        this.btnCancel.IsEnabled = false;
                        this.btnIgnore.IsEnabled = false;

                        this.exec();
                        break;
                    case xStatus.Pause:
                        this.btnRun.IsEnabled = true;
                        this.btnRun.Content = "继续";

                        this.btnCancel.IsEnabled = true;
                        this.btnIgnore.IsEnabled = false;
                        break;
                    
                    case xStatus.Continue:
                        this.btnRun.IsEnabled = true;
                        this.btnRun.Content = "暂停";
                        this.btnCancel.IsEnabled = false;
                        this.btnIgnore.IsEnabled = false;

                        this.execAsyncSignal.Set();
                        break;
                    case xStatus.Error:
                        this.btnRun.IsEnabled = true;
                        this.btnRun.Content = "重试";

                        this.btnCancel.IsEnabled = true;
                        this.btnIgnore.IsEnabled = true;
                        break;
                    case xStatus.Retry:
                    case xStatus.Ignore:
                        this.btnRun.IsEnabled = true;
                        this.btnRun.Content = "暂停";
                        this.btnCancel.IsEnabled = false;
                        this.btnIgnore.IsEnabled = false;

                        this.execAsyncSignal.Set();
                        break;
                    case xStatus.Cancel:
                        this.execAsyncSignal.Set();
                        break;
                }

                this.currentStatus = status;
            });
        }

        Action runContext = null;
        public void exec() {
            this.runContext.BeginInvoke(new AsyncCallback((IAsyncResult iar)=>{
                this.Dispatcher.BeginInvoke((Action)delegate() {
                    this.switch_status(xStatus.Idle);
                });
            }), null);
        }

        void message_clear() {
            this.Dispatcher.Invoke((Action)delegate() {
                this.rtbMessage.Document.Blocks.Clear();
            });
        }

        void message_new(string message, Brush color) {
            this.Dispatcher.Invoke((Action)delegate() {
                this.rtbMessage.Focus();
                this.rtbMessage.Document.Blocks.Add(new Paragraph(new Run(message) { Foreground = color }));
                this.rtbMessage.ScrollToEnd();
            });
        }
        #endregion
    }
}
